package com.example.es_promotion.service;

import com.example.es_promotion.entity.Promotion;
import com.example.es_promotion.document.EsPromotion;
import com.example.es_promotion.entity.CartItem;
import com.example.es_promotion.repository.PromotionRepository;
import com.example.es_promotion.repository.EsPromotionRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class PromotionService {
    
    private final PromotionRepository promotionRepository;
    private final EsPromotionRepository esPromotionRepository;
    
    @Transactional
    public Promotion createPromotion(Promotion promotion) {
        promotion.setStatus(0); // 待审批状态
        Promotion savedPromotion = promotionRepository.save(promotion);
        
        // 异步同步到ES（这里简化处理，实际应该用消息队列）
        syncToElasticsearch(savedPromotion);
        return savedPromotion;
    }
    
    @Transactional
    public Promotion updatePromotion(Long id, Promotion promotion) {
        Promotion existingPromotion = promotionRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Promotion not found"));
        
        existingPromotion.setName(promotion.getName());
        existingPromotion.setDescription(promotion.getDescription());
        existingPromotion.setStartTime(promotion.getStartTime());
        existingPromotion.setEndTime(promotion.getEndTime());
        existingPromotion.setPromotionType(promotion.getPromotionType());
        existingPromotion.setApplicableSkus(promotion.getApplicableSkus());
        existingPromotion.setApplicableCategories(promotion.getApplicableCategories());
        existingPromotion.setMinPrice(promotion.getMinPrice());
        existingPromotion.setMaxPrice(promotion.getMaxPrice());
        
        Promotion updatedPromotion = promotionRepository.save(existingPromotion);
        
        // 同步更新ES
        syncToElasticsearch(updatedPromotion);
        return updatedPromotion;
    }
    
    @Transactional
    public void approvePromotion(Long id) {
        Promotion promotion = promotionRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Promotion not found"));
        
        promotion.setStatus(1); // 已审批
        promotionRepository.save(promotion);
        
        // 同步到ES
        syncToElasticsearch(promotion);
    }
    
    @Transactional
    public void terminatePromotion(Long id) {
        Promotion promotion = promotionRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Promotion not found"));
        
        promotion.setStatus(2); // 已终止
        promotionRepository.save(promotion);
        
        // 从ES删除
        deleteFromElasticsearch(promotion.getId());
    }
    
    @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public void syncToElasticsearch(Promotion promotion) {
        try {
            EsPromotion esPromotion = convertToEsPromotion(promotion);
            esPromotionRepository.save(esPromotion);
            log.info("Successfully synced promotion {} to Elasticsearch", promotion.getId());
        } catch (Exception e) {
            log.error("Failed to sync promotion {} to Elasticsearch: {}", promotion.getId(), e.getMessage());
            throw e; // 触发重试
        }
    }
    
    @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public void deleteFromElasticsearch(Long promotionId) {
        try {
            esPromotionRepository.deleteById(promotionId.toString());
            log.info("Successfully deleted promotion {} from Elasticsearch", promotionId);
        } catch (Exception e) {
            log.error("Failed to delete promotion {} from Elasticsearch: {}", promotionId, e.getMessage());
            throw e; // 触发重试
        }
    }
    
    public List<Promotion> getCartPromotions(List<CartItem> cartItems) {
        List<Promotion> matchingPromotions = new ArrayList<>();
        
        for (CartItem item : cartItems) {
            // 提取商品属性
            List<String> skuIds = List.of(item.getSkuId());
            List<String> categoryIds = List.of(item.getCategoryId());
            Double price = item.getPrice();
            
            // 查询ES中匹配的活动
            List<EsPromotion> esPromotions = esPromotionRepository.findMatchingPromotions(
                    LocalDateTime.now().toString(),
                    skuIds,
                    categoryIds,
                    price
            );
            
            // 转换为业务实体
            List<Promotion> promotions = esPromotions.stream()
                    .map(this::convertToPromotion)
                    .collect(Collectors.toList());
            
            matchingPromotions.addAll(promotions);
        }
        
        return matchingPromotions.stream().distinct().collect(Collectors.toList());
    }
    
    public List<Promotion> getAllPromotions() {
        return promotionRepository.findAll();
    }
    
    public Promotion getPromotionById(Long id) {
        return promotionRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Promotion not found"));
    }
    
    private EsPromotion convertToEsPromotion(Promotion promotion) {
        EsPromotion esPromotion = new EsPromotion();
        esPromotion.setId(promotion.getId().toString());
        esPromotion.setPromotionId(promotion.getId());
        esPromotion.setName(promotion.getName());
        esPromotion.setDescription(promotion.getDescription());
        esPromotion.setStartTime(promotion.getStartTime());
        esPromotion.setEndTime(promotion.getEndTime());
        esPromotion.setStatus(promotion.getStatus());
        esPromotion.setPromotionType(promotion.getPromotionType());
        esPromotion.setApplicableSkus(promotion.getApplicableSkus());
        esPromotion.setApplicableCategories(promotion.getApplicableCategories());
        esPromotion.setMinPrice(promotion.getMinPrice());
        esPromotion.setMaxPrice(promotion.getMaxPrice());
        return esPromotion;
    }
    
    private Promotion convertToPromotion(EsPromotion esPromotion) {
        Promotion promotion = new Promotion();
        promotion.setId(esPromotion.getPromotionId());
        promotion.setName(esPromotion.getName());
        promotion.setDescription(esPromotion.getDescription());
        promotion.setStartTime(esPromotion.getStartTime());
        promotion.setEndTime(esPromotion.getEndTime());
        promotion.setStatus(esPromotion.getStatus());
        promotion.setPromotionType(esPromotion.getPromotionType());
        promotion.setApplicableSkus(esPromotion.getApplicableSkus());
        promotion.setApplicableCategories(esPromotion.getApplicableCategories());
        promotion.setMinPrice(esPromotion.getMinPrice());
        promotion.setMaxPrice(esPromotion.getMaxPrice());
        return promotion;
    }
}